#include <ip2regionUtil.h>
#include <filesystem>
#include <loguru.hpp>

namespace Util
{
    std::shared_ptr<xdb_search_t> Ip2RegionUtil::xdbPtr{nullptr};

    bool Ip2RegionUtil::init(const std::string &xdbFilePath)
    {
        if (!std::filesystem::exists(xdbFilePath))
        {
            return false;
        }
        xdbPtr = std::make_shared<xdb_search_t>(xdbFilePath);
        xdbPtr->init_content();
        return true;
    }

    ParseResult Ip2RegionUtil::getIpLocation(const std::string &ip)
    {
        ParseResult result;
        // ipv6地址
        if (ip.size() > 15)
        {
            result.ec = parse_erroc::is_ipv6;
            return result;
        }
        // xdbPtr未初始化
        if (xdbPtr == nullptr)
        {
            result.ec = parse_erroc::un_init;
            return result;
        }
        std::string location = xdbPtr->search(ip);
        // 解析失败
        if (location.empty() || location.find("invalid") != std::string::npos)
        {
            result.ec = parse_erroc::failed;
            return result;
        }

        // 解析成功
        result.ec = parse_erroc::success;
        return parseLocation(location);
    }

    ParseResult Ip2RegionUtil::parseLocation(const std::string &input)
    {
#ifdef _DEBUG
        LOG_F(INFO, "Ip2RegionUtil::parseLocation : %s\n", input.c_str());
#endif
        ParseResult result;
        std::vector<std::string> tokens;
        std::string token;
        std::stringstream ss(input);
        if (input.find("内网") != std::string::npos)
        {
            result.ec = parse_erroc::success;
            result.location = "内网";
            return result;
        }
        while (std::getline(ss, token, '|'))
        {
            tokens.emplace_back(token);
        }

        if (tokens.size() >= 4)
        {
            result.ec = parse_erroc::success;
            if (tokens[0].compare("0") != 0)
            {
                result.location.append(tokens[0]);
            }
            if (tokens[2].compare("0") != 0)
            {
                result.location.append("-" + tokens[2]);
            }
            if (tokens[3].compare("0") != 0)
            {
                result.location.append("-" + tokens[3]);
            }
            return result;
        }
        else
        {
            result.ec = parse_erroc::failed;
            return result;
        }
    }

    // ------------------------------ 错误处理 ------------------------------
    auto &parseErrorCategory()
    {

        {
            const static struct : public std::error_category
            {

                virtual const char *name() const noexcept
                {
                    return "ip2region";
                }

                virtual std::string message(int ec) const
                {
                    {
                        switch (parse_erroc(ec))
                        {
                        case parse_erroc::success:
                            return "解析成功！";
                        case parse_erroc::failed:
                            return "解析失败！";
                        case parse_erroc::un_init:
                            return "xdbPtr未初始化";
                        case parse_erroc::is_ipv6:
                            return "ipv6地址，暂时未解析";
                        default:
                            return "解析失败！";
                        }
                    }
                }
            } instance;
            return instance;
        }
    }

    std::error_code make_error_code(parse_erroc ec)
    {
        return std::error_code(int(ec), parseErrorCategory());
    }

    // ------------------------------ 错误处理 ------------------------------
}
